package com.ncucoder.soms.controller;

import com.ncucoder.soms.dto.*;
import com.ncucoder.soms.entity.User;
import com.ncucoder.soms.service.UserService;
import com.ncucoder.soms.util.JwtTokenUtils;
import io.swagger.annotations.*;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.Map;

/**
 * @author <a href="https://www.ncucoder.com">hsowan</a>
 * @date 2019-07-10
 **/
@RestController
@RequestMapping("/api/v1")
public class UserController {

    private Logger logger = LoggerFactory.getLogger(UserController.class);

    private final UserService userService;

    public UserController(UserService userService) {
        assert userService != null;
        this.userService = userService;
    }

    @ApiOperation("登录")
    @ApiImplicitParam(name = "User", value = "登录对象", dataTypeClass = LoginUserDTO.class, paramType = "body", required = true)
    @PostMapping("/user/login")
    public ResponseDTO login(@RequestBody LoginUserDTO loginUserDTO, HttpServletResponse response) {

        String username = loginUserDTO.getUsername();
        String password = loginUserDTO.getPassword();

        if (username == null || "".equals(username)) {
            logger.info("用户名不能为空");
            return new ResponseDTO(ResponseDTO.BAD_REQUEST, "用户名不能为空");
        }

        if (password == null || "".equals(password)) {
            logger.info("密码不能为空");
            return new ResponseDTO(ResponseDTO.BAD_REQUEST, "密码不能为空");
        }

        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        try {
            subject.login(token);

            // 更新用户登录时间
            userService.updateLastLoginByUsername(username, new Date());

            // 登录成功
            // 获取用户角色
            String role = userService.getRoleByUsername(username);

            // 生成jwtToken
            String jwtToken = JwtTokenUtils.createToken(username, role);
            response.setHeader(JwtTokenUtils.RESPONSE_TOKEN_HEADER, JwtTokenUtils.TOKEN_PREFIX + jwtToken);
            return new ResponseDTO(ResponseDTO.OK, "登录成功");

        } catch (AuthenticationException e) {
            // 登录失败
            logger.info(e.getMessage());
            return new ResponseDTO(ResponseDTO.BAD_REQUEST, "用户名或密码有误");
        }
    }

    @ApiOperation("获取用户信息")
    @GetMapping("/user")
    public ResponseDTO profile(HttpServletRequest request) {

        String username = (String) request.getAttribute("username");

        User user = userService.getUserByUsername(username);
        if (user != null) {
            return new ResponseDTO(ResponseDTO.OK, user);
        }
        return new ResponseDTO(ResponseDTO.SERVER_ERROR, ResponseDTO.SERVER_ERROR_MASSAGE);

    }

    @ApiOperation("创建新用户")
    @PostMapping("/user")
    public ResponseDTO createUser(@RequestBody CreateUserDTO createUserDTO, HttpServletResponse response) {
        // 这里不对CreateUserDTO做检查, 直接交给userService.createUser
        int r = userService.createUser(createUserDTO);
        if (r != 1) {
            response.setStatus(500);
            return new ResponseDTO(ResponseDTO.SERVER_ERROR, ResponseDTO.SERVER_ERROR_MASSAGE);
        }
        return new ResponseDTO(ResponseDTO.CREATED, "创建成功");
    }

    @ApiOperation("删除用户")
    @ApiImplicitParam(name = "id", value = "用户id", required = true, dataTypeClass = Long.class, paramType = "query")
    @DeleteMapping("/user")
    public ResponseDTO delete(@RequestParam Long id, HttpServletResponse response){
        if (id == null || id <= 0) {
            response.setStatus(400);
            return new ResponseDTO(ResponseDTO.BAD_REQUEST, "删除失败");
        }
        if (userService.deleteUserById(id) != 1) {
            response.setStatus(500);
            return new ResponseDTO(ResponseDTO.SERVER_ERROR, ResponseDTO.SERVER_ERROR_MASSAGE);
        }
        return new ResponseDTO(ResponseDTO.OK, "删除成功");
    }

    @PostMapping("/user/change_password")
    @ApiOperation("修改密码")
    @ApiImplicitParam(name = "newPassword", value = "新密码", dataTypeClass = Map.class, paramType = "body", required = true)
    public ResponseDTO changePassword(@RequestBody Map<String, String> map, HttpServletRequest request) {
        String newPassword = map.get("newPassword");
        String username = (String) request.getAttribute("username");
        if (userService.updatePasswordByUsername(newPassword, username) == 1) {
            return new ResponseDTO(ResponseDTO.OK, "修改成功");
        }
        return new ResponseDTO(ResponseDTO.SERVER_ERROR, ResponseDTO.SERVER_ERROR_MASSAGE);
    }

    @GetMapping("/users/count")
    @ApiOperation("获取用户总数")
    public ResponseDTO count() {

        int count = userService.countUsers();
        if (count >= 0) {
            return new ResponseDTO(ResponseDTO.OK, count);
        }
        return new ResponseDTO(ResponseDTO.SERVER_ERROR, ResponseDTO.SERVER_ERROR_MASSAGE);

    }

    @GetMapping("/users")
    @ApiOperation("分页获取用户")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", value = "当前页码, 默认值: 1", paramType = "query"),
            @ApiImplicitParam(name = "page_size", value = "每页展示的数目, 默认值: 10", paramType = "query")
    })
    public ResponseDTO listUsers(@RequestParam(defaultValue = "1", required = false) Integer page, @RequestParam(name = "page_size", defaultValue = "10", required = false) Integer pageSize) {

        int maxPageSize = 20;
        if (page <= 0 || pageSize <= 0 || pageSize > maxPageSize) {
            return new ResponseDTO(ResponseDTO.BAD_REQUEST, "参数范围不合法");
        }

        return new ResponseDTO(ResponseDTO.OK, userService.listUsers(page, pageSize));
    }

    @PostMapping("/user/update")
    @ApiOperation("更新用户信息")
    public ResponseDTO update(@RequestBody UpdateUserDTO updateUser) {
        int r = userService.updateUser(updateUser);
        if (r == 1) {
            return new ResponseDTO(ResponseDTO.OK, "更新成功");
        }
        return new ResponseDTO(ResponseDTO.BAD_REQUEST, "更新失败");
    }

}
